<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  

  
  <title>Netty的简单使用，实现socket通讯 | 海晨忆的博客</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  
  
  
  <meta name="description" content="自从用了netty框架，妈妈再也不用担心我的socket通讯了">
<meta property="og:type" content="article">
<meta property="og:title" content="Netty的简单使用，实现socket通讯">
<meta property="og:url" content="https://haichenyi.com/2018/02/08/Netty的简单使用，实现socket通讯/index.html">
<meta property="og:site_name" content="海晨忆的博客">
<meta property="og:description" content="自从用了netty框架，妈妈再也不用担心我的socket通讯了">
<meta property="og:locale" content="zh-Hans">
<meta property="og:updated_time" content="2018-02-22T12:59:18.347Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Netty的简单使用，实现socket通讯">
<meta name="twitter:description" content="自从用了netty框架，妈妈再也不用担心我的socket通讯了">
  
    <link rel="alternate" href="/atom.xml" title="海晨忆的博客" type="application/atom+xml">
  
  
    <link rel="icon" href="/uploads/artistic_image/head.jpg">
  
  
    <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  
  <link rel="stylesheet" href="/css/style.css">
  <link rel="stylesheet" href="/css/highlight.css">
  <script>
  let antiquityStorage = window.sessionStorage.getItem('antiquitySessionStorage');
  if (antiquityStorage == '' || antiquityStorage == null) {
    var antiquityLoader = '<div id="loaderbox"><div class="loader"><div class="load-roll"><div class="load-top"></div><div class="load-right"></div><div class="load-bottom"></div></div></div></div>';
    document.write(antiquityLoader);
    document.body.style.overflow = 'hidden'
  }
  </script>
</head>

<body>
  <div id="fullpage" class="mobile-nav-right">
    
      <div id="wrapper" style="background-image: url(/uploads/artistic_image/bg.jpg)" title="背景图片来自网络">
    
    
      <header id="header">
  <div id="nav-toggle" class="nav-toggle"></div>
  <div class="head-box global-width">
    <nav class="nav-box nav-right">
      
        <a class="nav-item" href="/" title
        
        >首页</a>
      
        <a class="nav-item" href="/archives" title
        
        >归档</a>
      
        <a class="nav-item" href="/about" title
        
        >简历</a>
      
    </nav>
  </div>
</header>
      <div id="middlecontent" title class="global-width sidebar-left">
        <section id="main"><article id="post-Netty的简单使用，实现socket通讯" class="article global-container article-type-post" itemscope itemprop="blogPost">
  
    <header class="article-header">
      
  
    <h1 class="article-title" itemprop="name">
      Netty的简单使用，实现socket通讯
    </h1>
  

    </header>
  
  <div class="article-meta">
    <a href="/2018/02/08/Netty的简单使用，实现socket通讯/" class="article-date">
  <time datetime="2018-02-08T13:46:05.000Z" itemprop="datePublished">2018-02-08</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/Android-Socket/">Android -Socket</a>
  </div>

    
  </div>
  
    <span id="busuanzi_container_page_pv">
      本文总阅读量<span id="busuanzi_value_page_pv"></span>次
    </span>
  

  <div class="article-inner">
    
    <div class="article-content article-content-cloud doorframe mac" itemprop="articleBody">
      
        <p>自从用了netty框架，妈妈再也不用担心我的socket通讯了<br><a id="more"></a><br>&emsp;&emsp;题外话，很多人都把JDK1.4提供的NIO称之为异步非阻塞I/O；其实，并不然，从严格意义上面讲，它只能称为非阻塞I/O。在JDK1.7提供的NIO 2.0，新增了异步的套接字通道Channel，它才是真正的异步非阻塞I/O。下表是不同I/O模型的对比：</p>
<p>表1-1 几种I/O模型和同能对比</p>
<table>
<thead>
<tr>
<th style="text-align:center"></th>
<th style="text-align:center">同步阻塞I/O(BIO)</th>
<th style="text-align:center">伪异步I/O</th>
<th style="text-align:center">非阻塞I/O(NIO)</th>
<th style="text-align:center">异步I/O(AIO)</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">客户端个数：I/O线程</td>
<td style="text-align:center">1:1</td>
<td style="text-align:center">M:N(M可以大于N)</td>
<td style="text-align:center">M:1(1个I/O线程处理多个客户端连接)</td>
<td style="text-align:center">M:0(不需要启动额外的I/O线程，被动回调)</td>
</tr>
<tr>
<td style="text-align:center">I/O类型(阻塞)</td>
<td style="text-align:center">阻塞I/O</td>
<td style="text-align:center">阻塞I/O</td>
<td style="text-align:center">非阻塞I/O</td>
<td style="text-align:center">非阻塞I/O</td>
</tr>
<tr>
<td style="text-align:center">I/O类型(同步)</td>
<td style="text-align:center">同步I/O</td>
<td style="text-align:center">同步I/O</td>
<td style="text-align:center">同步I/O(I/O多路复用)</td>
<td style="text-align:center">异步I/O</td>
</tr>
<tr>
<td style="text-align:center">API使用难度</td>
<td style="text-align:center">简单</td>
<td style="text-align:center">简单</td>
<td style="text-align:center">非常复杂</td>
<td style="text-align:center">复杂</td>
</tr>
<tr>
<td style="text-align:center">调试难度</td>
<td style="text-align:center">简单</td>
<td style="text-align:center">简单</td>
<td style="text-align:center">复杂</td>
<td style="text-align:center">复杂</td>
</tr>
<tr>
<td style="text-align:center">可靠性</td>
<td style="text-align:center">非常差</td>
<td style="text-align:center">差</td>
<td style="text-align:center">高</td>
<td style="text-align:center">高</td>
</tr>
<tr>
<td style="text-align:center">吞吐量</td>
<td style="text-align:center">低</td>
<td style="text-align:center">中</td>
<td style="text-align:center">高</td>
<td style="text-align:center">高</td>
</tr>
</tbody>
</table>
<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>&emsp;&emsp;Netty是由<a href="https://baike.baidu.com/item/JBOSS" target="_blank" rel="noopener">JBOSS</a>提供的一个<a href="https://baike.baidu.com/item/java%E5%BC%80%E6%BA%90" target="_blank" rel="noopener">java开源</a>框架。Netty提供异步的、<a href="https://baike.baidu.com/item/%E4%BA%8B%E4%BB%B6%E9%A9%B1%E5%8A%A8" target="_blank" rel="noopener">事件驱动</a>的网络应用程序框架和工具，用以快速开发高性能、高可靠性的<a href="https://baike.baidu.com/item/%E7%BD%91%E7%BB%9C%E6%9C%8D%E5%8A%A1%E5%99%A8" target="_blank" rel="noopener">网络服务器</a>和客户端程序。</p>
<p>&emsp;&emsp;也就是说，Netty 是一个基于NIO的客户、服务器端编程框架，使用Netty 可以确保你快速和简单的开发出一个网络应用，例如实现了某种协议的客户，<a href="https://baike.baidu.com/item/%E6%9C%8D%E5%8A%A1%E7%AB%AF" target="_blank" rel="noopener">服务端</a>应用。Netty相当简化和流线化了网络应用的编程开发过程，例如，TCP和UDP的socket服务开发。</p>
<p>&emsp;&emsp;“快速”和“简单”并不用产生维护性或性能上的问题。Netty 是一个吸收了多种协议的实现经验，这些协议包括FTP,SMTP,HTTP，各种二进制，文本协议，并经过相当精心设计的项目，最终，Netty 成功的找到了一种方式，在保证易于开发的同时还保证了其应用的性能，稳定性和伸缩性。——百度百科</p>
<h2 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h2><ol>
<li><p>API使用简单，开发门槛低</p>
</li>
<li><p>功能强大，预置了多种编解码功能，支持多种主流协议</p>
</li>
<li><p>性能高，通过与业界其他主流NIO框架相比，netty的综合性能最高</p>
</li>
<li><p>成熟，稳定，Netty已经修复了已经发现的所有的JDK NIO BUG，业务开发人员不用再为NIO的bug而烦恼</p>
</li>
<li><p>社区活跃，版本迭代周期短，发现bug可以及时被修复，同时有更多的新功能加入</p>
</li>
<li><p>经历了大规模的商界业务考验，只能得到了验证</p>
</li>
</ol>
<h2 id="粘包、拆包"><a href="#粘包、拆包" class="headerlink" title="粘包、拆包"></a>粘包、拆包</h2><h3 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h3><p>&emsp;&emsp;TCP是一个流协议，所谓的流，就是没有界限的一串数据。可以考虑河里的流水，他们并没有界限。tcp底层并不了解业务层数据的具体含义，他会根据tcp缓冲区的实际情况进行包的划分，所以在业务上认为，一个完整的包可能会被tcp拆分成多个包进行发送，也可能把多个小包封装成一个大数据一起发送，这就是所谓的tcp粘包，拆包问题</p>
<h3 id="产生原因"><a href="#产生原因" class="headerlink" title="产生原因"></a>产生原因</h3><ol>
<li><p>应用程序write写入的字节大小大于套接口发送缓冲区的大小</p>
</li>
<li><p>进行MSS大小的tcp分段</p>
</li>
<li><p>以太网帧的payload大于MTU进行IP分片</p>
</li>
</ol>
<h3 id="解决办法"><a href="#解决办法" class="headerlink" title="解决办法"></a>解决办法</h3><ol>
<li><p>消息定长，每个报文大小固定长度，不够的补0</p>
</li>
<li><p>包尾增加回车换行符进行分割。例如：FTP协议</p>
</li>
<li><p>将消息分为消息头和消息体。消息头中包含消息的总长度字段</p>
</li>
<li><p>更复杂的应用层协议</p>
</li>
</ol>
<h3 id="Netty框架的解决办法"><a href="#Netty框架的解决办法" class="headerlink" title="Netty框架的解决办法"></a>Netty框架的解决办法</h3><p>&emsp;&emsp;LineBasedFrameDecoder和StringDecoder两个类</p>
<h4 id="LineBasedFrameDecoder"><a href="#LineBasedFrameDecoder" class="headerlink" title="LineBasedFrameDecoder"></a>LineBasedFrameDecoder</h4><p>&emsp;&emsp;LineBasedFrameDecoder的工作原理是依次遍历ByteBuf中的可读字节，判断看是否有”\r”或者”\r\n”，如果有就以此为结束位置，从可读索引位置到结束区间的字节就组成了一行。他是以换行符为结束标志的解码器，支持携带结束符和不带结束符两种解码方式。同时支持配置单行的最大长度。如果连续读取到最大长度后仍然没有发现换行符，就会抛出异常，同时忽略掉之前读取的异常流</p>
<h4 id="StringDecoder"><a href="#StringDecoder" class="headerlink" title="StringDecoder"></a>StringDecoder</h4><p>&emsp;&emsp;StringDecoder的功能就非常简单，就是将接收到的对象换成字符串，然后继续调用后面的handler，LineBasedFrameDecoder+StringDecoder组合就是按换行符切换文本解码器，他被设计用来支持TCP粘包和拆包。Netty支持其他其他符号的解码器(DelimiterBasedFrameDecode)</p>
<p>&emsp;&emsp;说了这么多，代码来了，就是用Netty实现的心跳。对于懒癌晚期，已经风装好，可以直接拿过去用，注释也写的很清楚</p>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br></pre></td><td class="code"><pre><span class="line">import android.util.Log;</span><br><span class="line"></span><br><span class="line">import io.netty.bootstrap.Bootstrap;</span><br><span class="line">import io.netty.channel.Channel;</span><br><span class="line">import io.netty.channel.ChannelFuture;</span><br><span class="line">import io.netty.channel.ChannelInitializer;</span><br><span class="line">import io.netty.channel.ChannelOption;</span><br><span class="line">import io.netty.channel.ChannelPipeline;</span><br><span class="line">import io.netty.channel.EventLoopGroup;</span><br><span class="line">import io.netty.channel.nio.NioEventLoopGroup;</span><br><span class="line">import io.netty.channel.socket.SocketChannel;</span><br><span class="line">import io.netty.channel.socket.nio.NioSocketChannel;</span><br><span class="line">import io.netty.handler.codec.LineBasedFrameDecoder;</span><br><span class="line">import io.netty.handler.codec.string.StringDecoder;</span><br><span class="line">import io.netty.handler.codec.string.StringEncoder;</span><br><span class="line">import io.netty.util.CharsetUtil;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * @author 海晨忆</span><br><span class="line"> * @date 2018/2/6</span><br><span class="line"> * @desc</span><br><span class="line"> */</span><br><span class="line">public class SocketTcp &#123;</span><br><span class="line">  private static SocketTcp socketTcp = new SocketTcp();</span><br><span class="line">  private Channel channel = null;</span><br><span class="line">  private EventLoopGroup group;</span><br><span class="line">  private int port;</span><br><span class="line">  private String host;</span><br><span class="line"></span><br><span class="line">  public static SocketTcp getInstance() &#123;</span><br><span class="line">    return socketTcp;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  public SocketTcp setPort(int port) &#123;</span><br><span class="line">    this.port = port;</span><br><span class="line">    return this;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  public SocketTcp setHost(String host) &#123;</span><br><span class="line">    this.host = host;</span><br><span class="line">    return this;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  public void connect() &#123;</span><br><span class="line">    if (channel != null) return;</span><br><span class="line">    if (group == null) &#123;</span><br><span class="line">      //NIO线程组</span><br><span class="line">      group = new NioEventLoopGroup();</span><br><span class="line">    &#125;</span><br><span class="line">    try &#123;//配置Bootstrap</span><br><span class="line">      Bootstrap bootstrap = new Bootstrap();</span><br><span class="line">      bootstrap.group(group)</span><br><span class="line">          .channel(NioSocketChannel.class)</span><br><span class="line">          .option(ChannelOption.TCP_NODELAY, true)</span><br><span class="line">          .handler(new ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line">            @Override</span><br><span class="line">            protected void initChannel(SocketChannel ch) throws Exception &#123;</span><br><span class="line">              //以换行符为结束标记</span><br><span class="line">              ChannelPipeline pipeline = ch.pipeline();</span><br><span class="line">              pipeline.addLast(&quot;encoder&quot;, new StringEncoder(CharsetUtil.UTF_8));</span><br><span class="line">              pipeline.addLast(new LineBasedFrameDecoder(Integer.MAX_VALUE));</span><br><span class="line">              pipeline.addLast(new StringDecoder());</span><br><span class="line">              pipeline.addLast(new MyHeartSocket());</span><br><span class="line"></span><br><span class="line">              //以&quot;$_&quot;作为分隔符</span><br><span class="line">              /*ChannelPipeline pipeline = ch.pipeline();</span><br><span class="line">              pipeline.addLast(&quot;encoder&quot;, new StringEncoder(CharsetUtil.UTF_8));</span><br><span class="line">              String s = &quot;$_&quot;;</span><br><span class="line">              ByteBuf byteBuf = Unpooled.copiedBuffer(s.getBytes());</span><br><span class="line">              pipeline.addLast(new DelimiterBasedFrameDecoder(Integer.MAX_VALUE,byteBuf));</span><br><span class="line">              pipeline.addLast(new StringDecoder());</span><br><span class="line">              pipeline.addLast(new MyHeartSocket());*/</span><br><span class="line"></span><br><span class="line">            &#125;</span><br><span class="line">          &#125;);</span><br><span class="line">      //发起异步连接操作</span><br><span class="line">      ChannelFuture channelFuture = bootstrap.connect(host, port).sync();</span><br><span class="line">      channel = channelFuture.channel();</span><br><span class="line">      //等待服务端监听端口关闭</span><br><span class="line">      channel.closeFuture().sync();</span><br><span class="line">    &#125; catch (Exception e) &#123;</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">    &#125; finally &#123;</span><br><span class="line">      disConnect();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  /**</span><br><span class="line">   * 断开tcp连接.</span><br><span class="line">   */</span><br><span class="line">  private void disConnect() &#123;</span><br><span class="line">    if (null != group) &#123;</span><br><span class="line">      group.shutdownGracefully();</span><br><span class="line">    &#125;</span><br><span class="line">    group = null;</span><br><span class="line">    channel = null;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  public void sendMessage(String msg) &#123;//连接成功后，通过Channel提供的接口进行IO操作</span><br><span class="line">    try &#123;</span><br><span class="line">      if (channel != null &amp;&amp; channel.isOpen()) &#123;</span><br><span class="line">        channel.writeAndFlush(msg).sync();</span><br><span class="line">        Log.d(&quot;wz&quot;, &quot;send succeed &quot; + msg);</span><br><span class="line">      &#125; else &#123;</span><br><span class="line">        reConnect();</span><br><span class="line">        throw new Exception(&quot;channel is null | closed&quot;);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; catch (Exception e) &#123;</span><br><span class="line">      reConnect();</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  /**</span><br><span class="line">   * 重连.</span><br><span class="line">   */</span><br><span class="line">  private void reConnect() &#123;</span><br><span class="line">    new Thread(this::connect);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line">package com.example.zwang.myapplication.socket;</span><br><span class="line"></span><br><span class="line">import android.os.SystemClock;</span><br><span class="line">import android.util.Log;</span><br><span class="line"></span><br><span class="line">import java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line">import io.netty.buffer.ByteBuf;</span><br><span class="line">import io.netty.buffer.Unpooled;</span><br><span class="line">import io.netty.channel.ChannelHandlerContext;</span><br><span class="line">import io.netty.channel.EventLoop;</span><br><span class="line">import io.netty.channel.SimpleChannelInboundHandler;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">public class MyHeartSocket extends SimpleChannelInboundHandler&lt;Object&gt; &#123;</span><br><span class="line">  private ChannelHandlerContext ctx;</span><br><span class="line">  private boolean isConnect = false;</span><br><span class="line"></span><br><span class="line">  @Override</span><br><span class="line">  protected void messageReceived(ChannelHandlerContext ctx, Object msg) throws Exception &#123;</span><br><span class="line">    Log.v(&quot;WZ&quot;, &quot;连接正常messageReceived&quot;);</span><br><span class="line">    ByteBuf msg1 = (ByteBuf) msg;</span><br><span class="line">    byte[] bytes = new byte[msg1.readableBytes()];</span><br><span class="line">    msg1.readBytes(bytes);</span><br><span class="line">    String s = new String(bytes, &quot;UTF-8&quot;);</span><br><span class="line">    Log.v(&quot;WZ&quot;, &quot;接收到的消息:&quot; + s);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  @Override</span><br><span class="line">  public void channelActive(ChannelHandlerContext ctx) throws Exception &#123;</span><br><span class="line">    super.channelActive(ctx);</span><br><span class="line">    Log.v(&quot;WZ&quot;, &quot;连接正常channelActive&quot;);</span><br><span class="line">    isConnect = true;</span><br><span class="line">    if (this.ctx == null) &#123;</span><br><span class="line">      synchronized (MyHeartSocket.class) &#123;</span><br><span class="line">        if (this.ctx == null) &#123;</span><br><span class="line">          this.ctx = ctx;</span><br><span class="line">          MyAppHeart();</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  private void MyAppHeart() &#123;</span><br><span class="line">    new Thread(() -&gt; &#123;</span><br><span class="line">      while (ctx != null &amp;&amp; isConnect) &#123;</span><br><span class="line">        String data = &quot;123&quot;;</span><br><span class="line">        byte[] bytes = data.getBytes();</span><br><span class="line">        if (isConnect) &#123;</span><br><span class="line">          ctx.writeAndFlush(Unpooled.buffer(bytes.length).writeBytes(bytes));</span><br><span class="line">          SystemClock.sleep(3000);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;).start();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  @Override</span><br><span class="line">  public void channelInactive(ChannelHandlerContext ctx) throws Exception &#123;</span><br><span class="line">    EventLoop loop = ctx.channel().eventLoop();</span><br><span class="line">    loop.schedule(() -&gt; SocketTcp.getInstance().connect(), 5, TimeUnit.SECONDS);</span><br><span class="line">    super.channelInactive(ctx);</span><br><span class="line">    Log.v(&quot;WZ&quot;, &quot;重新连接socket服务器&quot;);</span><br><span class="line">    isConnect = false;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  @Override</span><br><span class="line">  public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception &#123;</span><br><span class="line">    super.userEventTriggered(ctx, evt);</span><br><span class="line">    Log.v(&quot;WZ&quot;, &quot;发送数据包&quot;);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  @Override</span><br><span class="line">  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception &#123;</span><br><span class="line">    super.exceptionCaught(ctx, cause);</span><br><span class="line">    Log.v(&quot;WZ&quot;, &quot;连接出现异常&quot;);</span><br><span class="line">    this.ctx.close();</span><br><span class="line">    this.ctx = null;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>

      
    </div>
    
      <footer class="article-footer">
        完
      </footer>
    
  </div>
  
    
<nav id="article-nav">
  <div class="article-nav-block">
    
      <a href="/2018/02/08/Android自定义View/" id="article-nav-newer" class="article-nav-link-wrap">
        <strong class="article-nav-caption"></strong>
        <div class="article-nav-title">
          
            Android自定义View
          
        </div>
      </a>
    
  </div>
  <div class="article-nav-block">
    
      <a href="/2018/02/07/IO编程和NIO编程简介/" id="article-nav-older" class="article-nav-link-wrap">
        <div class="article-nav-title">IO编程和NIO编程简介</div>
        <strong class="article-nav-caption"></strong>
      </a>
    
  </div>
</nav>

    
  
  
</article>
</section>
        <aside id="sidebar">
  
    <div class="widget-box">
  <div class="avatar-box avatar-item">
    <img class="avatar" src="/uploads/artistic_image/head.jpg" title="头像来自网络"></img>
    <h3 class="avatar-name">
      
        海晨忆
      
    </h3>
    <p class="avatar-slogan">
      先谋生，再谋爱。人间值得，未来可期。
    </p>
  </div>
</div>


  
    
  <div class="widget-box">
    <h3 class="widget-title">分类</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/Android-Socket/">Android -Socket</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-加密算法/">Android -加密算法</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-常用功能/">Android -常用功能</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-框架/">Android -框架</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-源码解析/">Android -源码解析</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-自定义view/">Android -自定义view</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-设计模式/">Android -设计模式</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/JAVA-并发/">JAVA -并发</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java-SpringBoot/">Java -SpringBoot</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Tomcat/">Tomcat</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/kotlin/">kotlin</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/数据库-JDBC/">数据库 -JDBC</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/数据库-MySQL/">数据库 -MySQL</a></li></ul>
    </div>
  </div>


  
    

  
    
  
    
  <div class="widget-box">
    <h3 class="widget-title">归档</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/07/">July 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/11/">November 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/10/">October 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/09/">September 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/08/">August 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/07/">July 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/06/">June 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/10/">October 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/05/">May 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/03/">March 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/02/">February 2018</a></li></ul>
    </div>
  </div>

  
    
  <div class="widget-box">
    <h3 class="widget-title">最新文章</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2021/07/27/JAVA—公平锁，非公平锁，悲观锁，乐观锁，死锁/">JAVA—公平锁，非公平锁，悲观锁，乐观锁，死锁</a>
          </li>
        
          <li>
            <a href="/2021/07/19/JAVA—线程同步器AQS/">JAVA—线程同步器AQS</a>
          </li>
        
          <li>
            <a href="/2021/07/07/Android模拟点击/">Android模拟点击</a>
          </li>
        
          <li>
            <a href="/2019/11/27/SpringBoot系列-消息-RabbitMQ-（二十）/">SpringBoot系列-消息(RabbitMQ)（二十）</a>
          </li>
        
          <li>
            <a href="/2019/11/13/SpringBoot系列-Docker（十九）/">SpringBoot系列-Docker（十九）</a>
          </li>
        
      </ul>
    </div>
  </div>

  
      <div class="widget-box">
    <h3 class="widget-title">友情链接</h3>
    <div class="widget">
      
        <a class="hrf" style="display: block;" href="https://github.com/haichenyi" title target='_blank'
        >Github</a>
      
        <a class="hrf" style="display: block;" href="https://www.jianshu.com/u/6077ee440c37" title target='_blank'
        >简书</a>
      
        <a class="hrf" style="display: block;" href="https://blog.csdn.net/qq_27634797" title target='_blank'
        >CSDN</a>
      
    </div>
  </div>

  
</aside>
      </div>
      <footer id="footer">
  <div class="foot-box footers global-width">
    &copy;2017-2021 海晨忆 &nbsp;&nbsp;
    <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span id="busuanzi_container_site_pv">阁下是第<span id="busuanzi_value_site_pv"></span>个访客</span>
  </div>
</footer>
      <script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script>
if (!window.jQuery) {
var script = document.createElement('script');
script.src = "/js/jquery-2.0.3.min.js";
document.body.write(script);
}
</script>

  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css">
  <script src="/fancybox/jquery.fancybox.pack.js"></script>


<script src="/js/script.js"></script>



    </div>
    <nav id="mobile-nav" class="mobile-nav-box">
  <div class="mobile-nav-img mobile-nav-top"></div>
  
    <a href="/" class="mobile-nav-link">首页</a>
  
    <a href="/archives" class="mobile-nav-link">归档</a>
  
    <a href="/about" class="mobile-nav-link">简历</a>
  
  <div class="mobile-nav-img  mobile-nav-bottom"></div>
</nav>    
  </div>
</body>
</html>